iT邦幫忙

2024 iThome 鐵人賽

DAY 6
0
自我挑戰組

ROS 筆記:要怎麼叫無人機自己飛系列 第 6

【ROS 筆記:要怎麼叫無人機自己飛】Day 6:使用 Python 撰寫 ROS 節點(Node)

  • 分享至 

  • xImage
  •  

這篇會介紹用 Python 寫簡單的 ROS 節點,在之後寫功能更複雜一點的通訊節點還有控制無人機的程式時,就會根據這一篇的結構來延伸和擴充。

建立 ROS 節點

ROS 的節點(Node)是 ROS 通訊網路的基本單位,每一個執行特定功能(如讀取感測器資料、控制馬達轉速等)的程序會被視為一個節點。

一個套件內通常會包含多個節點,ROS 支援一個套件內存在不同的程式語言寫的節點(常見的有 Python、C++),再藉由 ROS 系統串接形成一個完整功能的套件。

一個節點的基本結構

使用 rospy 函式庫,就能用 Python 來編寫 ROS 的節點。

回到上一篇建好的 my_package/src 目錄,在這裡示範建立一個節點 create_node.py,程式內容如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import rospy
import random

def simple_node():
    # 初始化ROS節點
    rospy.init_node('simple_node', anonymous=True)
    
    # 設定頻率,這裡設定為1Hz
    rate = rospy.Rate(1)
    
    # 檢查節點是否被關閉
    while not rospy.is_shutdown():

        # 輸出日誌訊息
        hello_str = f"Hello ROS world {random.randint(1, 10)}"
        rospy.loginfo(hello_str)
        rospy.loginfo("Node is running...")
        
        # 控制循環頻率
        rate.sleep()

if __name__ == '__main__':
    try:
        simple_node()
    # 捕捉程序中斷異常並安全退出
    except rospy.ROSInterruptException: 
        pass

這是一個節點常見的程式結構:

  1. 節點初始化(Node Initialization):

    任何節點開始運作之前都必須先初始化,它會向主節點(Master)註冊自己的名稱,以便日後與其他節點進行通訊。

    rospy.init_node('simple_node', anonymous=True) 這行就是用來初始化這個節點,同時也會設定節點名稱,我先取名為 simple_node

    在 ROS 系統中,節點的通訊是透過彼此的名稱來找到對方,因此每一個節點都必須是獨一無二的名稱。如果不想費盡心思取名,就可以在初始化時將 anonymous 參數設為 True,那麼 ROS 系統會自動為這個節點名稱後面加上一串隨機生成的數字。

  2. 節點操作:

    在這個示範程式中使用了幾個常用的函式:

    • 節點是否被關閉:rospy.is_shutdown() 這個函式是代表當前節點是否被中止。

    • 設定頻率和休眠:rate = rospy.Rate(1) 是設定循環頻率 1 Hz,搭配休眠函式 rate.sleep() 維持程式執行速度輸出訊息。另一種常見的暫停方法是使用 rospy.sleep(time) ,當程式執行到這裡時會強制休眠指定時間。

    • 輸出日誌訊息:rospy.loginfo() 這行將會在終端機輸出訊息。

執行 ROS 節點

在 Day 3 提過主節點(Master)是一種特殊節點,它負責維護一個名稱服務(Name Service)的表格,裡面儲存每一個節點的名字,以便他們找到彼此並建立連結。

假如我們直接執行剛才寫好的 create_node.py ,會得到類似以下的錯誤訊息:

$ python3 create_node.py 
Unable to register with master node [http://localhost:11311]: master may not be running yet. Will keep trying.

這是在說主節點(Master)尚未啟動, ROS 系統無法向主節點註冊節點 simple_node。 因此在啟動任何其他節點之前必須先啟動主節點。

roscore 啟動主節點

啟動主節點的方式是在另一個終端機視窗執行 roscore 指令:

$ roscore

這個指令會啟動一個新的主節點,讓它來負責協調和管理所有節點的通訊。roscore 也會啟動其他核心服務和工具,例如參數伺服器(Parameter server)、 rosout ( 日誌節點) 和 roslaunch (套件啟動工具)。

  • 參數伺服器(Parameter server):

    參數伺服器是 ROS 系統中一個全域的儲存空間,它會儲存全域的配置設定或變數,任一節點都可以讀取或修改這些參數。例如,有一個負責移動機器人的節點和一個負責擷取影像的節點,這兩個節點都需要知道機器人的最大速度,這個「最大速度」參數就可以儲存在參數伺服器中,則不管是哪個節點,都能從同一個地方讀取或更新「最大速度」參數。

  • rosout (日誌節點) :

    rosout 也是一個特殊節點,負責集中處理和記錄 ROS 系統中的日誌訊息。

  • roslaunch (套件啟動工具):

    roslaunch 是用來啟動一個套件中多個節點的工具,套件必須先建立 .launch 檔(XML 格式的啟動檔案),則 roslaunch 就會根據啟動設定來依序啟動特定節點。

此時重新執行 create_node.py ,就可以看到程式開始輸出日誌訊息了:

$ python3 create_node.py 
[INFO] [1724252218.628211]: Hello ROS world 6
[INFO] [1724252218.629642]: Node is running...
[INFO] [1724252219.629879]: Hello ROS world 9
[INFO] [1724252219.633996]: Node is running...
[INFO] [1724252220.629656]: Hello ROS world 10
[INFO] [1724252220.632700]: Node is running...

rosrun 啟動特定節點

我們也可以使用指令 rosrun 從指定的 ROS 套件中執行一個節點,這個方法可以不用特別跑到檔案所在位置來執行檔案(尤其用 C++ 撰寫節點則編譯後執行檔會放在其他地方),並且也不需要指定直譯器(不用再輸入 python3 了)。

格式:

rosrun <package_name> <executable>

Python 撰寫的節點在第一次執行時需要先用 chmod +x 修改權限指令,讓這個檔案成為可執行檔(executable file)。其中chmod(change mode)這個指令可以用於改變檔案或目錄的存取權限。+x 表示給予檔案增加執行(execute)權限。

以前面建立的 create_node.py 為例:

$ chmod +x create_node.py

$ rosrun my_package create_node.py 
[INFO] [1724253103.219538]: Hello ROS world 3
[INFO] [1724253103.221236]: Node is running...
[INFO] [1724253104.220890]: Hello ROS world 4
[INFO] [1724253104.223521]: Node is running...
[INFO] [1724253105.221048]: Hello ROS world 7
[INFO] [1724253105.224848]: Node is running...

注意 rosrun 需要指定套件名稱,因此如果沒有建立套件便無法使用。


現在我們有了第一個 ROS 節點啦!雖然並沒有做太多特別的事情,甚至連機器人的一點邊都沒有碰到,但是沒關係,預計下一篇就會稍微有一點點機器人的內容了。


上一篇
【ROS 筆記:要怎麼叫無人機自己飛】Day 5:要怎麼建立一個 ROS 套件(Package)
下一篇
【ROS 筆記:要怎麼叫無人機自己飛】Day 7:透過 TurtleSim 來熟悉 ROS 節點常用指令
系列文
ROS 筆記:要怎麼叫無人機自己飛14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言